﻿using System.Collections.Concurrent;
using System.Diagnostics;
using System.Runtime.Intrinsics.X86;
using System.Threading.Tasks;

namespace SimdTest2.Methods
{
    public abstract class AlgorithmBase
    {
        protected readonly long _size;
        protected readonly int _row;
        protected readonly int _column;

        public AlgorithmBase(int row, int col)
        {
            _size = row * col;
            _row = row;
            _column = col;
            CreateData();
            N = 1;
            bool status = Sse2.IsSupported;
            Trace.WriteLine($"Sse2 IsSupported：{status}");
            status = Sse41.IsSupported;
            Trace.WriteLine($"Sse41 IsSupported：{status}");
        }
        public int N { get; set; }
        /// <summary>
        /// 算法运行类别
        /// 0全部，1普通算法，2simd算法
        /// </summary>
        public int RunAlgorithmType {  get; set; }
        protected virtual void CreateData() { }
        public virtual async Task<ConcurrentDictionary<string, RunTimes>> AssembleMethodAsync()
        {
            ConcurrentDictionary<string, RunTimes> _runTime = new ConcurrentDictionary<string, RunTimes>();
            List<Task> tasks = new List<Task>(RunAlgorithmType == 0 ? 2 : 1);
            if(RunAlgorithmType==0 || RunAlgorithmType == 1)
            {
                var task1 = Task.Run(() =>
                {
                    RunTimes times = new RunTimes();
                    List<RunTime> runTimes = new List<RunTime>(N);
                    times.Time = runTimes;
                    long t = 0;
                    Process currentProcess = Process.GetCurrentProcess();
                    long startCpuUsage = currentProcess.TotalProcessorTime.Ticks;
                    long startTime = DateTime.Now.Ticks;
                    Stopwatch sw = Stopwatch.StartNew();
                    for (int i = 0; i < N; i++)
                    {
                        OrdinaryMethod();
                        long a = sw.ElapsedMilliseconds;
                        runTimes.Add(new RunTime
                        {
                            Index = i + 1,
                            Time = a - t
                        });
                        t = a;
                    }
                    sw.Stop();
                    long endCpuUsage = currentProcess.TotalProcessorTime.Ticks;
                    long endTime = DateTime.Now.Ticks;
                    // 计算CPU使用率
                    double cpuUsage = (endCpuUsage - startCpuUsage) / (endTime - startTime) * 100 / Environment.ProcessorCount;
                    times.CpuUsage = cpuUsage;
                    times.Avg = sw.ElapsedMilliseconds / (double)N;
                    _runTime.TryAdd("OrdinaryMethod", times);
                });
                tasks.Add(task1);
            }

            if (RunAlgorithmType == 0 || RunAlgorithmType == 2)
            {
                var task2 = Task.Run(() =>
                {
                    RunTimes times = new RunTimes();
                    List<RunTime> runTimes = new List<RunTime>(N);
                    times.Time = runTimes;
                    long t = 0;
                    Process currentProcess = Process.GetCurrentProcess();
                    long startCpuUsage = currentProcess.TotalProcessorTime.Ticks;
                    long startTime = DateTime.Now.Ticks;
                    Stopwatch sw = Stopwatch.StartNew();
                    for (int i = 0; i < N; i++)
                    {
                        SimdMethod();
                        long a = sw.ElapsedMilliseconds;
                        runTimes.Add(new RunTime
                        {
                            Index = i + 1,
                            Time = a - t
                        });
                        t = a;
                    }
                    sw.Stop();
                    long endCpuUsage = currentProcess.TotalProcessorTime.Ticks;
                    long endTime = DateTime.Now.Ticks;
                    // 计算CPU使用率
                    double cpuUsage = (endCpuUsage - startCpuUsage) / (endTime - startTime) * 100 / Environment.ProcessorCount;
                    times.CpuUsage = cpuUsage;
                    times.Avg = sw.ElapsedMilliseconds / (double)N;
                    _runTime.TryAdd("SimdMethod", times);
                });
                tasks.Add(task2);
            }

            await Task.WhenAll(tasks);
            return _runTime;
        }
        protected abstract void OrdinaryMethod();
        protected abstract void SimdMethod();
    }
}
